// compile: g++ -o concurrent concurrent.cc -std=c++14
// run: ./concurrent

#include <chrono>
#include <future>
#include <iostream>
#include <mutex>
#include <thread>

using namespace std;
using namespace std::chrono_literals;  // C++14
mutex output_lock;

// jthread的一个简单实现
class scoped_thread {
 public:
  template <typename... Arg>
  scoped_thread(Arg&&... arg) : thread_(std::forward<Arg>(arg)...) {}
  scoped_thread(scoped_thread&& other) : thread_(std::move(other.thread_)) {}
  scoped_thread(const scoped_thread&) = delete;
  ~scoped_thread() {
    if (thread_.joinable()) {
      thread_.join();
    }
  }

 private:
  thread thread_;
};
void func(const char* name) {
  this_thread::sleep_for(100ms);
  lock_guard<mutex> guard{output_lock};
  cout << "I am thread " << name << '\n';
}
void Test1() {
  scoped_thread t1{func, "A"};
  scoped_thread t2{func, "B"};
}

int work1() {
  // 假装我们计算了很久
  this_thread::sleep_for(2s);
  return 42;
}
void Test2() {
  auto fut = async(launch::async, work1);
  // 干一些其他事
  this_thread::sleep_for(4s);
  cout << "I am waiting now\n";
  cout << "Answer: " << fut.get() << '\n';
}

// 优点：不需要在一个函数结束的时候才去设置 future 的值。
// 仍然需要注意的是，一组 promise 和 future
// 只能使用一次，既不能重复设，也不能重复取。
void work2(std::promise<int> prom) {
  // 假装我们计算了很久
  this_thread::sleep_for(2s);
  prom.set_value(42);
}
void Test3() {
  promise<int> prom;
  auto fut = prom.get_future();
  scoped_thread th(work2, move(prom));
  // 干一些其他事
  this_thread::sleep_for(1s);
  cout << "I am waiting now\n";
  cout << "Answer: " << fut.get() << '\n';
}

// thread、future、promise、packaged_task 只能移动，不能复制。
// packaged_task是个函数对象，可以像正常函数一样被执行，
int work3() {
  // 假装我们计算了很久
  this_thread::sleep_for(2s);
  return 42;
}
void Test4() {
  packaged_task<int()> pt(work3);
  auto fut = pt.get_future();
  scoped_thread th(move(pt));
  // 干一些其他事
  this_thread::sleep_for(1s);
  cout << "I am waiting now\n";
  cout << "Answer: " << fut.get() << '\n';
}
int main() {
  // Test1();
  // Test2();
  // Test3();
  Test4();
}
